package com.sikaryofficial.backend.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sikaryofficial.backend.constant.MyStatisticsTypeEnum;
import com.sikaryofficial.backend.domain.dto.req.information.ArticleEvaluateReplyListReq;
import com.sikaryofficial.backend.domain.dto.req.information.ArticleEvaluateReplyReq;
import com.sikaryofficial.backend.domain.dto.resp.information.ArticleEvaluateReplyDTO;
import com.sikaryofficial.backend.domain.entity.ArticleEvaluateReply;
import com.sikaryofficial.backend.domain.mapping.ArticleEvaluateReplyMapping;
import com.sikaryofficial.backend.domain.vo.EvaluateReplyCount;
import com.sikaryofficial.backend.domain.vo.ObjectCount;
import com.sikaryofficial.backend.mapper.ArticleEvaluateReplyMapper;
import com.sikaryofficial.backend.service.IArticleEvaluateReplyService;
import com.sikaryofficial.backend.service.IAttachmentService;
import com.sikaryofficial.backend.service.IMyStatisticsService;
import com.sikaryofficial.backend.service.user.UserCacheService;
import com.sikaryofficial.backend.service.useraction.cache.UserActionCacheService;
import com.sikaryofficial.common.security.utils.SecurityUtils;
import com.sikaryofficial.system.api.model.att.AttachmentResp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 文章评价回复Service业务层处理
 *
 * @author qinjinyuan
 * @date 2024-03-15
 */
@Service
@Slf4j
public class ArticleEvaluateReplyServiceImpl extends ServiceImpl<ArticleEvaluateReplyMapper, ArticleEvaluateReply> implements IArticleEvaluateReplyService {
    @Autowired
    private ArticleEvaluateReplyMapper articleEvaluateReplyMapper;
    @Autowired
    private IAttachmentService attachmentService;
    @Autowired
    private UserCacheService userCacheService;
    @Autowired
    private UserActionCacheService userActionCacheService;
    @Autowired
    private IMyStatisticsService myStatisticsService;

    /**
     * 统计评价下的回复数量
     *
     * @param evaluateIds
     * @return
     */
    @Override
    public List<EvaluateReplyCount> countByEvaluateId(List<Long> evaluateIds) {
        if (CollUtil.isEmpty(evaluateIds)) {
            return Collections.emptyList();
        }
        return articleEvaluateReplyMapper.countByEvaluateId(evaluateIds,SecurityUtils.getUserId());
    }

    /**
     * 根据多个评价ID分组查询回复列表
     *
     * @param evaluateIds
     * @param limitNum
     * @return
     */
    @Override
    public List<ArticleEvaluateReplyDTO> queryByEvaluateId(List<Long> evaluateIds, int limitNum) {
        List<ArticleEvaluateReplyDTO> replyRecords = articleEvaluateReplyMapper.queryByEvaluateId(evaluateIds, limitNum,SecurityUtils.getUserId());
        // 1、填充头像数据
        Map<Long, String> userAvatarMap = userCacheService.getMultiUserAvatar(replyRecords.stream().map(ArticleEvaluateReplyDTO::getCreatedBy).collect(Collectors.toList()));
        // 填充昵称
        Map<Long, String> userNickNameMap = userCacheService.getMultiUserNickName(replyRecords.stream().map(ArticleEvaluateReplyDTO::getCreatedBy).collect(Collectors.toList()));
        replyRecords.forEach(item -> {
            item.setAvatar(MapUtils.getString(userAvatarMap, item.getCreatedBy(), ""));
            item.setNickName(MapUtils.getString(userNickNameMap, item.getCreatedBy(), ""));
        });
        // 2、填充用户行为数据
        buildUserActionData(replyRecords);
        // 3、填充附件
        List<Long> replyIds = replyRecords.stream().map(ArticleEvaluateReplyDTO::getArticleEvaluateReplyId).collect(Collectors.toList());
        Map<Long, List<AttachmentResp>> attachmentMap = attachmentService.getAttachmentByIds(replyIds);
        replyRecords.forEach(item -> item.setAttachmentList(attachmentMap.get(item.getArticleEvaluateReplyId())));
        return replyRecords;
    }

    /**
     * 构建评价的点赞统计及个人点赞数据
     *
     * @param result
     */
    @Override
    public void buildUserActionData(List<ArticleEvaluateReplyDTO> result) {
        if (CollUtil.isEmpty(result)) {
            return;
        }
        try {
            // 填充每条跟评对应的点赞数量
            processArticleData(result);
            // 是否自己点赞
            result.stream().filter(Objects::nonNull).forEach(this::checkUserActions);
        } catch (NullPointerException e) {
            log.error("Null pointer exception occurred. Possibly due to null element in the result list or null context in processing.", e);
        } catch (IllegalArgumentException e) {
            log.error("Illegal argument exception occurred. Check the validity of the input data.", e);
        } catch (Exception e) {
            // 捕获其他未预期的异常
            log.error("Unexpected exception occurred during processing: {}", e.getMessage(), e);
        }
    }

    /**
     * 文章评价回复列表
     *
     * @param customerPage
     * @param req
     * @return
     */
    @Override
    public IPage<ArticleEvaluateReplyDTO> replyList(Page<ArticleEvaluateReplyDTO> customerPage, ArticleEvaluateReplyListReq req) {
        return articleEvaluateReplyMapper.replyList(customerPage, req, SecurityUtils.getUserId());
    }

    /**
     * 回复需要再保存后，返回对象
     *
     * @param req
     * @return
     */
    @Override
    public ArticleEvaluateReplyDTO saveReply(ArticleEvaluateReplyReq req) {
        Long replyId = IdWorker.getId();
        Long userId = SecurityUtils.getUserId();
        ArticleEvaluateReply articleEvaluateReply = ArticleEvaluateReply
                .builder()
                .replyUserId(req.getReplyUserId())
                .replyUserName(req.getReplyUserName())
                .replyType(req.getReplyType())
                .articleEvaluateReplyId(replyId)
                .articleEvaluateId(req.getArticleEvaluateId())
                .replyContent(req.getReplyContent())
                .createdTime(new Date())
                .createdName(SecurityUtils.getUsername())
                .createdBy(userId)
                .build();

        attachmentService.saveAttachmentList(replyId, req.getAttachmentList(),
                SecurityUtils.getUserId());
        this.save(articleEvaluateReply);

        ArticleEvaluateReplyDTO result = ArticleEvaluateReplyMapping.INSTANCE.coverToDTO(articleEvaluateReply);
        result.setAttachmentList(req.getAttachmentList());
        return result;
    }

    private void checkUserActions(ArticleEvaluateReplyDTO item) {
        if (Objects.nonNull(item.getLikesCount()) && item.getLikesCount() > 0) {
            item.setHasOwnerLikes(userActionCacheService.getOwnerAction(SecurityUtils.getUserId(), item.getArticleEvaluateReplyId(),
                    MyStatisticsTypeEnum.LIKES_ARTICLE_EVALUATE_REPLY.getBusinessType()));
        }
    }

    private void processArticleData(List<ArticleEvaluateReplyDTO> result) {
        // 点赞数量填充
        List<ObjectCount> objectCountList = myStatisticsService.countByObjectIds(result.stream().map(ArticleEvaluateReplyDTO::getArticleEvaluateReplyId).collect(Collectors.toList()));
        Map<Long, List<ObjectCount>> objectCountMap = objectCountList.stream().collect(Collectors.groupingBy(ObjectCount::getObjectId));
        result.forEach(replyDTO -> processCountData(replyDTO, objectCountMap));
    }

    private void processCountData(ArticleEvaluateReplyDTO replyDTO, Map<Long, List<ObjectCount>> objectCountMap) {
        List<ObjectCount> objectCounts = MapUtils.getObject(objectCountMap, replyDTO.getArticleEvaluateReplyId());
        if (CollUtil.isNotEmpty(objectCounts)) {
            populateLikesCount(replyDTO, objectCounts);
        }
    }

    private void populateLikesCount(ArticleEvaluateReplyDTO replyDTO, List<ObjectCount> objectCounts) {
        objectCounts.stream()
                .filter(e -> MyStatisticsTypeEnum.LIKES_ARTICLE_EVALUATE_REPLY.getBusinessType().equals(e.getBusinessType()))
                .findFirst()
                .ifPresent(e -> replyDTO.setLikesCount(e.getObjectCount()));
    }
}
